/*****************************************************************************
 * Copyright (c) 2010 -, Anders All rights reserved
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 *  Contact: Anders Uddenberg (anders.uddenberg@gmail.com)
 * 
 *
 ****************************************************************************/
package org.easypr.organizer.client;

/*
 * http://code.google.com/intl/sv-SE/appengine/docs/java/gettingstarted/usingdatastore.html
 * http://code.google.com/intl/sv-SE/appengine/docs/java/datastore/queriesandindexes.html#Queries_on_Keys
 * http://code.google.com/intl/sv-SE/appengine/docs/java/datastore/creatinggettinganddeletingdata.html
 * http://code.google.com/intl/sv-SE/webtoolkit/doc/latest/tutorial/mvp-architecture.html
 */

import java.util.ArrayList;

import org.easypr.organizer.client.event.DisplayInformationEvent;
import org.easypr.organizer.client.event.DisplayInformationEventHandler;
import org.easypr.organizer.client.event.DisplaySearchResultEvent;
import org.easypr.organizer.client.event.DisplaySearchResultEventHandler;
import org.easypr.organizer.client.presenter.BrowsePresenter;
import org.easypr.organizer.client.presenter.ContactPresenter;
import org.easypr.organizer.client.presenter.CreatePresenter;
import org.easypr.organizer.client.presenter.DashboardPresenter;
import org.easypr.organizer.client.presenter.ImportPresenter;
import org.easypr.organizer.client.presenter.MenuPresenter;
import org.easypr.organizer.client.presenter.Presenter;
import org.easypr.organizer.client.presenter.RegisterPresenter;
import org.easypr.organizer.client.presenter.SearchPresenter;
import org.easypr.organizer.client.presenter.SearchResultPresenter;
import org.easypr.organizer.client.presenter.SubmenuPresenter;
import org.easypr.organizer.client.presenter.InformationPresenter;
import org.easypr.organizer.client.view.BrowseView;
import org.easypr.organizer.client.view.ContactView;
import org.easypr.organizer.client.view.CreateView;
import org.easypr.organizer.client.view.DashboardView;
import org.easypr.organizer.client.view.ImportView;
import org.easypr.organizer.client.view.InformationView;
import org.easypr.organizer.client.view.MenuView;
import org.easypr.organizer.client.view.RegisterView;
import org.easypr.organizer.client.view.SearchResultView;
import org.easypr.organizer.client.view.SearchView;
import org.easypr.organizer.client.view.SubmenuView;
import org.easypr.organizer.shared.MyContact;
import org.easypr.organizer.shared.MyUser;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.RootPanel;

// TODO: Auto-generated Javadoc
/**
 * The Class AppController.
 */
public class AppController implements Presenter, ValueChangeHandler<String> {
	
	/** The event bus. */
	private final HandlerManager eventBus;
	
	/** The user rpc. */
	private MyUserServiceAsync userRPC;
	
	/** The backbone rpc. */
	private BackboneServiceAsync backboneRPC;
	
	

	/**
	 * Instantiates a new app controller.
	 *
	 * @param backboneRPC the backbone rpc
	 * @param eventBus the event bus
	 */
	public AppController(BackboneServiceAsync backboneRPC, HandlerManager eventBus) {
		this.backboneRPC = backboneRPC;
		this.eventBus = eventBus;
		bind();
	}

	
	
	/**
	 * Bind.
	 */
	private void bind() {
		History.addValueChangeHandler(this);
		
		/**
		 * Bind some handlers to our bus
		 * This makes sure that the application can respond to events placed
		 * on the bus.
		 * 
		 * Here the AppController has an instance of the HandlerManager, called eventBus, 
		 * and is registering a new DisplayErrorEventHandler. 
		 * This handler will grab the message and pass it to the doDisplayError() method 
		 * whenever an event of DisplayErrorEvent.getAssociatedType() is fired. 
		 * 
		 * Multiple components can be listening for a single event, so when an event is 
		 * fired using the HandlerManager.fireEvent(), the HandlerManager looks for any 
		 * component that has added a handler for event.getAssociatedType(). 
		 * For each component that has a handler, the HandlerManager calls event.dispatch() 
		 * with that component's EventHandler interface.
		 * 
		 */
		
		eventBus.addHandler(DisplaySearchResultEvent.TYPE,
				new DisplaySearchResultEventHandler() {
					public void onDisplaySearchResult(DisplaySearchResultEvent event) {
						doDisplaySearchResult(event.getContacts(), event.getUser());
					}
				}
		);
		
		eventBus.addHandler(DisplayInformationEvent.TYPE,
				new DisplayInformationEventHandler() {
					public void onDisplayInformation(DisplayInformationEvent event) {
						doDisplayInformation(event.getMessage(), event.getSeverity());
					}
				}
		);
	}
	
	/**
	 * Do display information.
	 *
	 * @param message the message
	 * @param severity the severity
	 */
	private void doDisplayInformation(String message, DisplayInformationEvent.Severity severity) {
		Presenter presenter = new InformationPresenter(eventBus, new InformationView(), message, severity);
		presenter.go(RootPanel.get("information"));
	}

	/**
	 * Do display search result.
	 *
	 * @param contacts the contacts
	 * @param user the user
	 */
	private void doDisplaySearchResult(final ArrayList<MyContact> contacts, MyUser user) {
		
		AsyncCallback<MyUser> callback = new AsyncCallback<MyUser>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(MyUser user) {
				//Presenter presenter = new SearchResultPresenter(contacts, eventBus, new SearchResultView(), user);
				//presenter.go(RootPanel.get("content"));
			}
			
		};
		userRPC.getUser(callback);
		
	}
	
	/**
	 * We're using the History to fire off different states.
	 * 
	 * @param container the container
	 */
	public void go(final HasWidgets container) {
		if ("".equals(History.getToken())) {
			History.newItem("dashboard");
		} else {
			History.fireCurrentHistoryState();
		}
		/*
		if(userRPC == null) {
			userRPC = GWT.create(MyUserService.class);
		}
		
		AsyncCallback<MyUser> callback = new AsyncCallback<MyUser>() {
			public void onFailure(Throwable caught) {
			}

			public void onSuccess(MyUser user) {
				
				if(user.isRegistered()) {
					if ("".equals(History.getToken())) {
						History.newItem("dashboard");
					} else {
						History.fireCurrentHistoryState();
					}
				} else {
					AsyncCallback<String> callback = new AsyncCallback<String>() {
						public void onFailure(Throwable caught) {
						}
						public void onSuccess(String result) {
							Window.Location.replace(result);
						}
					};
					userRPC.getLoginURL(Window.Location.getHref(), callback);
				}
			}
		};
		
		// Making sure the user is logged in
		userRPC.getUser(callback);
		*/
	}

	/**
	 * Declares what will happen when an item is added to the History stack
	 * 
	 * 
	 * One of the one more integral parts of any web app is the handling of history events.
	 * History events are token strings that represent some new state within your application.
	 * Think of them as "markers" for where you are in the application.
	 * Take, for example, a user navigating from the "Forum List" view to the "Topic" view and
	 * then clicking the "Back" button. The resulting action should land the user back
	 * on the "Forum List" view, and to do so you would push the initial
	 * state (the "Forum List" view) onto the history stack followed by a push of the "Topic" view.
	 * Thus when they click the back button the "Topic" token will be popped off of the
	 * stack and the current history token will be the "Forum List" view.
	 * 
	 * @param event the event
	 */
	public void onValueChange(ValueChangeEvent<String> event) {
		final String queryString = event.getValue();
		
		if (queryString != null) {
			

			
			if(userRPC == null) {
				userRPC = GWT.create(MyUserService.class);
			}
			
			AsyncCallback<MyUser> callback = new AsyncCallback<MyUser>() {
				public void onFailure(Throwable caught) {
				}

				public void onSuccess(MyUser user) {
					if(user.getNickname().length() == 0) {
						// We didn't have him in the session AND he is not logged in as a Google User
						// Move him to Google's login service
						AsyncCallback<String> callback = new AsyncCallback<String>() {
							public void onFailure(Throwable caught) {
							}
							public void onSuccess(String result) {
								Window.Location.replace(result);
							}
						};
						userRPC.getLoginURL(Window.Location.getHref(), callback);
						
						
						
					} else {
						Presenter presenter = null;
						// We either had him in the session or he's JUST
						// logged in as a Google User
						if(user.isRegistered()) {
							// Found him in the session and he's a user here, everything is fine
							//System.out.println("Finns i session och är användare här");
							
							// Sometimes we're passing some additional data
							// in the token that we want to extract and make use of
							// See this a a queryString (?variable=value)
							String[] parts = queryString.split("/");
							String token = parts[0];

							if(token.equals("search")) {
								presenter = new SearchPresenter(backboneRPC, eventBus, new SearchView(), user, parts);
							} else {
								presenter = new SearchPresenter(backboneRPC, eventBus, new SearchView(), user, null);
							}
							presenter.go(RootPanel.get("search")); 

							presenter = new SubmenuPresenter(eventBus, new SubmenuView(), user);
							presenter.go(RootPanel.get("submenu"));
							
							presenter = new MenuPresenter(eventBus, new MenuView());
							presenter.go(RootPanel.get("menu"));

							// Do different things depending on the token
							if (token.equals("dashboard")) {
								// Display the dashboard
								presenter = new DashboardPresenter(backboneRPC, eventBus, new DashboardView(), user);
								presenter.go(RootPanel.get("content"));
							} else if(token.equals("create")) {
								presenter = new CreatePresenter(backboneRPC, eventBus, new CreateView());
								presenter.go(RootPanel.get("content"));
							} else if(token.equals("browse")) {
								presenter = new BrowsePresenter(backboneRPC, eventBus, new BrowseView(), user, parts);
								presenter.go(RootPanel.get("content"));
							} else if(token.equals("search")) {
								presenter = new SearchResultPresenter(backboneRPC, eventBus, new SearchResultView(), user, parts);
								presenter.go(RootPanel.get("content"));
							} else if(token.equals("contact")) {
								presenter = new ContactPresenter(backboneRPC, eventBus, new ContactView(), user, parts);
								presenter.go(RootPanel.get("content"));
							} else if(token.equals("import")) {
								presenter = new ImportPresenter(backboneRPC, eventBus, new ImportView(), user, parts);
								presenter.go(RootPanel.get("content"));
							}
							
						} else {
							// He's logged in as a Google User
							// Process to register here
							RootPanel.get("register").addStyleName("register");
							presenter = new RegisterPresenter(backboneRPC, eventBus, new RegisterView(), user);
							presenter.go(RootPanel.get("register"));
							RootPanel.get("content-table").setVisible(false);
						}
					}
				}
				
			}; 
			
			// Making sure the user is logged in
			userRPC.getUser(callback);
		}
	}
}

